//////////////////////////////////////////////////////////////////////////
#include <RocketLua/RocketLua.hpp>


using namespace Rocket::Core::Lua;


//////////////////////////////////////////////////////////////////////////
const char*	LuaEventListener::mpListenerTable	=	"EventListenerTable";



LuaEventListener::LuaEventListener( lua_State* state, const Rocket::Core::String& code, Rocket::Core::Element* element )
:	Rocket::Core::EventListener()
,	mRefCount( 0 )
,	mpState( state )
,	mLuaRef( -1 )
{
	std::string		function	=	std::string( "return function ( event, element, document ) " ) + code.CString() + " end";

	lua_getglobal( mpState, mpListenerTable );
	if( lua_isnoneornil( mpState, -1 ) )
	{
		lua_newtable( mpState );
		lua_setglobal( mpState, mpListenerTable );
		lua_pop( mpState, 1 );
		lua_getglobal( mpState, mpListenerTable );
	}

	if( luaL_loadstring( mpState, function.c_str() ) != LUA_OK )
	{
		return;
	}

	if( lua_pcall( mpState, 0, 1, 0 ) != LUA_OK )
	{
		return;
	}

	mLuaRef	=	luaL_ref( mpState, -2 );
	lua_pop( mpState, 1 );
}


LuaEventListener::~LuaEventListener()
{
	lua_getglobal( mpState, mpListenerTable );
	luaL_unref( mpState, -1, mLuaRef );
}


void LuaEventListener::ProcessEvent( Rocket::Core::Event& event )
{
	int	top	=	lua_gettop( mpState );
	lua_getglobal( mpState, mpListenerTable );
	lua_rawgeti( mpState, -1, mLuaRef );

	// Event.
	luabridge::LuaRef	ev( mpState, &event );
	ev.push( mpState );

	// Element.
	luabridge::LuaRef	element( mpState, event.GetTargetElement() );
	element.push( mpState );

	// Document.
	luabridge::LuaRef	document( mpState, event.GetTargetElement()->GetOwnerDocument() );
	document.push( mpState );

	lua_pcall( mpState, 3, 0, -1 );
	lua_settop( mpState, top );
}


void LuaEventListener::OnAttach( Rocket::Core::Element* element )
{
	++mRefCount;
}


void LuaEventListener::OnDetach( Rocket::Core::Element* element )
{
	if( (--mRefCount) == 0 )
	{
		delete this;
	}
}
